// /////////////////////////////////////////////////////////////////////////////
//
// Name:            GameManager.cpp
// Author:          Michael Bartsch (ZCCdark203)
//
// Desc :           The Game Manager is the central access point to the game.
//                  It is able to perform generic game initialisation and
//                  deinitialisation. It's main purpose, though, is to control
//                  the flow of the game.
//
// License:         Copyright (C) 2009 Michael Bartsch and Contributors
//
//                  This program is free software: you can redistribute it
//                  and/or modify it under the terms of the zlib/libpng License.
//                  See main.cpp for conditions of distribution and use.
//
// /////////////////////////////////////////////////////////////////////////////

// Include files
#include "GameManager.h"
#include "../game/InitState.h"


// GameManager class
// Constructor of the GameManager class.
GameManager::GameManager()
: pDevice(0), mLastTime(0)
{
}

// Deconstructor of the GameManager class.
GameManager::~GameManager()
{
    clear();
}

// GameManager singleton.
GameManager* GameManager::pInstance = 0;

GameManager* GameManager::Instance()
{
    if(pInstance == 0)
      pInstance = new GameManager();

    return pInstance;
}

GameManager& GameManager::Reference()
{
    if(pInstance == 0)
      pInstance = new GameManager();

    return *pInstance;
}

// Initialises the GameManager.
void GameManager::init()
{
    // Initialise the subsystems of the framework. (stage 1)
    pDataStore = new DataStore();
    pEventManager = new EventManager();

    // Initialise the Irrlicht engine.
    pDevice = createDevice(EDT_OPENGL, dimension2d<u32>(1024, 768), 32, false, false, false, pEventManager);

    // Get points to subsystems of the Irrlicht engine.
    pDriver = pDevice->getVideoDriver();
    pSceneManager = pDevice->getSceneManager();
	pGUIEnvironment = pDevice->getGUIEnvironment();

	// Initialise subsystems of the framework (stage 2);
	pAssetManager = new AssetManager();
	pAssetManager->init();

	pEntityManager = new EntityManager();

#ifdef __COMPILE_WITH_SFML_AUDIO__
	pSoundManager = new SoundManager();
#endif // __COMPILE_WITH_SFML_AUDIO__

#ifdef __COMPILE_WITH_ANGELSCRIPT__
	pScriptManager = new ScriptManager();
	pScriptManager->init();
#endif // __COMPILE_WITH_ANGELSCRIPT__

    // Change to the init state.
    GameState *state = new InitState();
    changeState(state);
    state->drop();
}

// Updates the GameManager.
void GameManager::update()
{
    // Updating
    u32 time = pDevice->getTimer()->getTime();
    f32 deltaTime = ( (float)time - (float)mLastTime ) *0.01f;
    mLastTime = time;

    if(!mGameStates.empty() && deltaTime > 0.0f)
    {
        mGameStates.back()->onUpdate(deltaTime);
        mGameStates.back()->update(deltaTime);
    }

    // Rendering
    if(pDevice->isWindowActive())
    {
       if(!mGameStates.empty())
       {
          pDriver->beginScene();

          mGameStates.back()->render();
          mGameStates.back()->onRender();

          pSceneManager->drawAll();
          pGUIEnvironment->drawAll();

          pDriver->endScene();
       }
    }
}

// Clears the GameManager.
void GameManager::clear()
{
    // Clean up the state stack.
    while(!mGameStates.empty())
    {
       mGameStates.back()->clear();
       mGameStates.back()->drop();
       mGameStates.pop_back();
    }

    // Clean up subsystems of the framework.
#ifdef ____COMPILE_WITH_ANGELSCRIPT__
    pScriptManager->clear();
    delete pScriptManager;
#endif // __COMPILE_WITH_ANGELSCRIPT__

#ifdef __COMPILE_WITH_SFML_AUDIO__
    delete pSoundManager;
#endif // __COMPILE_WITH_SFML_AUDIO__

    delete pEntityManager;

    pAssetManager->clear();
    delete pAssetManager;

    delete pEventManager;
    delete pDataStore;

    // Clean up Irrlicht.
    pDevice->drop();
}

// Increases the reference counter.
void GameManager::grab()
{
    // Dummy function.
}

// Decreases the reference counter.
void GameManager::drop()
{
    // Dummy function.
}

// Close the current state and change to the given state.
void GameManager::changeState(GameState *state)
{
    // Clear the current state.
    popState();

    // Initialise the state.
    if(state != NULL)
    {
        mGameStates.push_back(state);
        state->grab();
        state->init();
    }
}

// Pause the current state and change to the given state.
void GameManager::pushState(GameState *state)
{
    // Pause the current state.
    if(!mGameStates.empty())
      mGameStates.back()->onPause();

    // Initialise the state.
    if(state != NULL)
    {
       mGameStates.push_back(state);
       state->grab();
       state->init();
    }
}

// Close the current state and resume the previous state.
void GameManager::popState()
{
    // Clear the current state.
    if(!mGameStates.empty())
    {
       mGameStates.back()->clear();
       mGameStates.back()->drop();
       mGameStates.pop_back();
    }

    // Unpause the newly selected state.
    if(!mGameStates.empty())
      mGameStates.back()->onUnPause();
}

// Returns a pointer to the Irrlicht Device.
IrrlichtDevice* GameManager::getDevice()
{
	return pDevice;
}

// Returns a pointer to the Irrlicht driver.
IVideoDriver* GameManager::getDriver()
{
	return pDriver;
}

// Returns a pointer to the Irrlicht SceneManager.
ISceneManager* GameManager::getSceneManager()
{
	return pSceneManager;
}

// Returns a pointer to the Irrlicht GUI Manager.
IGUIEnvironment* GameManager::getGUIEnvironment()
{
	return pGUIEnvironment;
}

// Returns a pointer to the AssetManager.
AssetManager* GameManager::getAssetManager()
{
    return pAssetManager;
}

// Returns a pointer to the DataStore.
DataStore* GameManager::getDataStore()
{
    return pDataStore;
}

// Returns a pointer to the EntityManager.
EntityManager* GameManager::getEntityManager()
{
    return pEntityManager;
}

// Returns a pointer to the EventManager.
EventManager* GameManager::getEventManager()
{
    return pEventManager;
}

#ifdef __COMPILE_WITH_ANGELSCRIPT__

// Returns a pointer to the ScriptManager.
ScriptManager* GameManager::getScriptManager()
{
    return pScriptManager;
}

#endif // __COMPILE_WITH_ANGELSCRIPT__

#ifdef __COMPILE_WITH_SFML_AUDIO__

// Returns a pointer to the Sound Manager.
SoundManager* GameManager::getSoundManager()
{
    return pSoundManager;
}

#endif // __COMPILE_WITH_SFML_AUDIO__

// Returns whether the Irrlicht device is running.
bool GameManager::getIsRunning() const
{
    return pDevice->run();
}

// Sets the running state of the Irrlicht device.
// --> Wrapper function for pDevice->closeDevice()
void GameManager::setIsRunning(bool value)
{
    if(value == false)
      pDevice->closeDevice();
}

// End of File
